/**
 * 
 */
package org.statewalker.fsm.util;

import org.statewalker.fsm.FsmProcess;
import org.statewalker.fsm.IFsmProcessListener;

/**
 * This class is used to print state traces of a process.
 * 
 * @author kotelnikov
 */
public class PrintStateListener<S, E> implements IFsmProcessListener<S, E> {

    private int fDepth;

    private boolean fShowStates;

    private boolean fShowTransitions;

    /**
     * 
     */
    public PrintStateListener() {
        this(true, true);
    }

    /**
     * @param showStates
     * @param showTransitions
     */
    public PrintStateListener(boolean showStates, boolean showTransitions) {
        fShowStates = showStates;
        fShowTransitions = showTransitions;
    }

    /**
     * @see org.statewalker.fsm.IFsmProcessListener#beginState(org.statewalker.fsm.FsmProcess,
     *      java.lang.Object)
     */
    public void beginState(FsmProcess<S, E> process, S state) {
        if (fShowStates) {
            String name = getStateName(state);
            println("<" + name + ">");
        }
        fDepth++;
    }

    /**
     * @see org.statewalker.fsm.IFsmProcessListener#endState(org.statewalker.fsm.FsmProcess,
     *      java.lang.Object)
     */
    public void endState(FsmProcess<S, E> process, S state) {
        fDepth--;
        if (fShowStates) {
            String name = getStateName(state);
            println("</" + name + ">");
        }
    }

    /**
     * Returns the name of the given process event. This method could be
     * overloaded in subclasses.
     * 
     * @param event the event for which the name should be returned
     * @return the name of the given process event
     */
    protected String getEventName(E event) {
        return event != null ? event.toString() : null;
    }

    /**
     * Returns the name of the given state. This method could be overloaded in
     * subclasses.
     * 
     * @param state the state for which the name should be returned
     * @return the name of the given state
     */
    protected String getStateName(S state) {
        return state != null ? state.toString() : null;
    }

    /**
     * @see org.statewalker.fsm.IFsmProcessListener#onTransition(org.statewalker.fsm.FsmProcess,
     *      java.lang.Object, java.lang.Object, java.lang.Object)
     */
    public void onTransition(FsmProcess<S, E> process, S prev, E event, S next) {
        if (fShowTransitions) {
            S parent = process.getCurrentState();
            println("<transition parent='"
                + getStateName(parent)
                + "' from='"
                + getStateName(prev)
                + "' event='"
                + getEventName(event)
                + "' to='"
                + getStateName(next)
                + "' />");
        }
    }

    /**
     * Prints out the given string. This method can be overloaded in subclasses.
     * 
     * @param string the string to print.
     */
    public void print(String string) {
        System.out.print(string);
    }

    /**
     * This method prints out the given string with indentation depending on the
     * depth of the current state.
     * 
     * @param string the string to print out
     */
    public void println(String string) {
        for (int i = 0; i < fDepth; i++) {
            print("    ");
        }
        print(string);
        print("\n");
    }

}
